/******************************************************************************
 * * contact_select.c - implementation of contact selection functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "contact_global.h"

/**
 * Callback function for handling key pressed on the interface to select one contact
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Com_Select_One_Contact_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta,
                                             UI_KEY_VALUE Key_Val)
{
    UINT8                      Ret        = 1;
    UI_Button_Container_Desc_t *Interface =
        &(((UI_Normal_Button_Container_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl)->ButtonContainer);
    UINT16                     ContactTotal;

    if (CONTACTS_MEMSEL_ALL != g_ContactsMng.ContactsMemSel.MemSel)
    {
        ContactTotal = g_ContactsMng.ContactsMemSel.ContactsCount;
    }
    else
    {
        ContactTotal = g_ContactsMng.ContactsCount;
    }

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_UP:
        case KEY_LEFT:
        case KEY_DOWN:
        case KEY_RIGHT:
            Ret =
                Contacts_Press_Direction_Key(Key_Val, Interface, &g_ContactsMng.InterfaceCtrl.Focus);
            break;

        case KEY_OK:
            if (0 != ContactTotal)
            {
                Ret = 0; // call the default key function
            }
            break;

        case KEY_SOFTRIGHT:
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        default:
            break;
        } /* switch */
    }

    return(Ret);
} /* Contacts_Com_Select_One_Contact_Key_Cb */

/**
 * Callback function for additional actions after Creating Contacts_Select_One
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_One_Contact_OnCreate(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t *                        Cont       = Interface->ButtonContainer.ContScrl.Container;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    if (0 < ContactsCount)
    {
        ScrlH = ContactsCount * Interface->ButtonContainer.Height;
        Contacts_Set_ScrlBar_Size_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH);
        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH, 0);
    }
}

/**
 * Callback function for additional actions after restoring Contacts_Select_One
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_One_Contact_OnRestoreState(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t *                        Cont       = Interface->ButtonContainer.ContScrl.Container;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    if (0 < ContactsCount)
    {
        ScrlH = ContactsCount * Interface->ButtonContainer.Height;
        Contacts_Set_ScrlBar_Size_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH);
        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->ButtonContainer.List,
                                             ScrlH,
                                             - Interface->ButtonContainer.PosY);
    }
}

/**
 * Callback function for destroying Contacts_Select_One interface which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_One_Contact_OnDestroy(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    UINT8 i;

    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        if (NULL != Interface->ButtonContainer.ContButton[i].BtnTxt)
        {
            Hal_Mem_Free(Interface->ButtonContainer.ContButton[i].BtnTxt);
        }
    }
    Hal_Mem_Free(Ctrl);
    g_ContactsMng.InterfaceCtrl.Focus = NULL;
}

/**
 * Common function for the interface to select one contact
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Com_Create_Select_One_Contact(ACTIVITY_ID ForwardId, lv_event_cb_t BtnRelFun)
{
    UI_Normal_Button_Container_Desc_t *Interface;
    Nav_Func_List_t                   FuncList;
    UINT8                             Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH +
                                            1;
    Contacts_List_t                   *Contact;
    lv_ll_t                           *ContactsList;
    UINT16                            ContactsCount;
    UINT8                             i;

    Interface =
        (UI_Normal_Button_Container_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_Button_Container_Desc_t));
    Hal_Mem_Set(Interface, 0, sizeof(UI_Normal_Button_Container_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_SELECT_ONE;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)Interface;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactsCount);

    Interface->TitleBar.TxtId      = PHONE_TEXT_ID_CONTACT;
    Interface->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    Interface->Label.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->Label.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    if (0 == ContactsCount)
    {
        Interface->Label.TxtId            = PHONE_TEXT_ID_EMPTY;
        g_ContactsMng.InterfaceCtrl.Focus = NULL;
    }
    else
    {
        Interface->Label.TxtId = LV_LANG_TXT_ID_NONE;

        Contact = _lv_ll_get_head(ContactsList);
        g_ContactsMng.InterfaceCtrl.Focus = Contact;

        for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
        {
            if (Contact)
            {
                Interface->ButtonContainer.ContButton[i].Valid       = TRUE;
                Interface->ButtonContainer.ContButton[i].ButtonIndex = i;
                Interface->ButtonContainer.ContButton[i].TxtId       = LV_LANG_TXT_ID_NONE;            
                Interface->ButtonContainer.ContButton[i].SymbolId2   = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
                Interface->ButtonContainer.ContButton[i].BtnTxt      = (INT8 *)Hal_Mem_Alloc(Len);
                sprintf(Interface->ButtonContainer.ContButton[i].BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
                Interface->ButtonContainer.ContButton[i].ReleaseFun = BtnRelFun;

                Contact = _lv_ll_get_next(ContactsList, Contact);
            }
            else
            {
                break;
            }
        }

        /* if (0 != (FP_CONT_BAR_H % ContactsCount)) */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / ContactsCount + 1; */
        /* } */
        /* else */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / ContactsCount; */
        /* } */
        Interface->ButtonContainer.Height = FP_CONT_BAR_H / UI_MAX_CONT_BTN_NUM;
    }

    Interface->ButtonBar.ButtonL.Valid = FALSE;

    Interface->ButtonBar.ButtonM.Valid = TRUE;
    Interface->ButtonBar.ButtonM.TxtId = PHONE_TEXT_ID_SELECT;

    Interface->ButtonBar.ButtonR.Valid = TRUE;
    Interface->ButtonBar.ButtonR.TxtId = PHONE_TEXT_ID_BACK;

    Interface->KeyFunc = Contacts_Com_Select_One_Contact_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_Button_Container_Create;
    FuncList.OnCreate       = Contacts_Com_Select_One_Contact_OnCreate;
    FuncList.OnRestoreState = Contacts_Com_Select_One_Contact_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Com_Select_One_Contact_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ForwardId, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Com_Select_One_Contact */

/**
 * Action if pressing contact button on Contacts_Select_One interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Select_One_Btn_Contact_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Info_t      *Contact = g_ContactsMng.InterfaceCtrl.Focus->ContactInfo;
    INT8                 *Name;
    INT8                 *Number;
    If_Contacts_Select_t *ContactSel;

    switch (g_ContactsMng.SelectContactType)
    {
    case IF_CONTACTS_CALL_SEL_ONE_CONTACT:
        Name = (INT8 *)Hal_Mem_Alloc(CONTACTS_MAX_NAME_LENGTH);
        Hal_Mem_Copy(Name, Contact->Name, CONTACTS_MAX_NAME_LENGTH);
        Number = (INT8 *)Hal_Mem_Alloc(CONTACTS_MAX_NUMBER_LENGTH);
        Hal_Mem_Copy(Number, Contact->Number, CONTACTS_MAX_NUMBER_LENGTH);
        Contacts_Call_Select_Contact_Cnf(Name, Number);
        break;

    case IF_CONTACTS_SETTING_SEL_ONE_CONTACT:
        Number = (INT8 *)Hal_Mem_Alloc(CONTACTS_MAX_NUMBER_LENGTH);
        Hal_Mem_Copy(Number, Contact->Number, CONTACTS_MAX_NUMBER_LENGTH);
        Contacts_Setting_Select_Contact_Cnf(Number);
        break;

    case IF_CONTACTS_SMS_SEL_ONE_CONTACT:
        ContactSel = (If_Contacts_Select_t *)Hal_Mem_Alloc(sizeof(If_Contacts_Select_t));
        Hal_Mem_Copy(ContactSel->Name, Contact->Name, CONTACTS_MAX_NAME_LENGTH);
        Hal_Mem_Copy(ContactSel->Number, Contact->Number, CONTACTS_MAX_NUMBER_LENGTH);
        Contacts_SMS_Select_Contact_Cnf(ContactSel, 1);
        break;

    default:
        break;
    }
}

/**
 * Create Contacts_Select_One interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Select_One(VOID)
{
    Contacts_Com_Create_Select_One_Contact(ACT_ID_CONTACTS_SELECT_ONE, Contacts_Select_One_Btn_Contact_Cb);
}

/**
 * Action if pressing select all or contact button on the interface to select multiple contacts
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Com_Select_Multi_Contacts_Btn_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    UI_Button_Container_Desc_t *Interface =
        &(((UI_Normal_Button_Container_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl)->
              ButtonContainer);
    Contacts_List_t *Contact = g_ContactsMng.InterfaceCtrl.Focus;
    lv_ll_t         *ContactsList;
    lv_obj_t        *Image;
    UINT16          Count;
    UINT8           i;

    ContactsList = Contacts_Get_Contacts_Operation_List(&Count);

    if (NULL == Contact) // foucs on select all button at the first position
    {
        if (0 != Interface->Index)
        {
            /* error */
            return;
        }

        if (FALSE == g_ContactsMng.InterfaceCtrl.SelAllFlg)
        {
            /* select all contacts */
            g_ContactsMng.InterfaceCtrl.SelAllFlg = TRUE;
            g_ContactsMng.ContactOper.MarkNum     = Count;

            for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
            {
                if (TRUE == Interface->ContButton[i].Valid)
                {
                    Interface->ContButton[i].SymbolId1 = SYMBOL_CHECKED;
                    Image                              = lv_obj_get_child_back(Interface->ContButton[i].Button, NULL);
                    lv_img_set_src(Image, SYMBOL_CHECKED);
                }
                else
                {
                    break;
                }
            }
        }
        else
        {
            /* not select all contacts */
            g_ContactsMng.InterfaceCtrl.SelAllFlg = FALSE;
            g_ContactsMng.ContactOper.MarkNum     = 0;

            for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
            {
                if (TRUE == Interface->ContButton[i].Valid)
                {
                    Interface->ContButton[i].SymbolId1 = SYMBOL_NOT_CHECKED;
                    Image                              = lv_obj_get_child_back(Interface->ContButton[i].Button, NULL);
                    lv_img_set_src(Image, SYMBOL_NOT_CHECKED);
                }
                else
                {
                    break;
                }
            }
        }

        Contact = _lv_ll_get_head(ContactsList);
        while (NULL != Contact)
        {
            Contact->ContactInfo->MarkFlg = g_ContactsMng.InterfaceCtrl.SelAllFlg;

            Contact = _lv_ll_get_next(ContactsList, Contact);
        }
    }
    else
    {
        if (TRUE == Contact->ContactInfo->MarkFlg)
        {
            Contact->ContactInfo->MarkFlg = FALSE;
            if (TRUE == g_ContactsMng.InterfaceCtrl.SelAllFlg)
            {
                g_ContactsMng.InterfaceCtrl.SelAllFlg = FALSE;
                if (PHONE_TEXT_ID_SELECT_ALL == Interface->ContButton[0].TxtId)
                {
                    Image = lv_obj_get_child_back(Interface->ContButton[0].Button, NULL);
                    lv_img_set_src(Image, SYMBOL_NOT_CHECKED);
                }
            }
            g_ContactsMng.ContactOper.MarkNum--;

            Interface->ContButton[Interface->Index].SymbolId1 = SYMBOL_NOT_CHECKED;
        }
        else
        {
            Contact->ContactInfo->MarkFlg = TRUE;
            g_ContactsMng.ContactOper.MarkNum++;
            if (Count == g_ContactsMng.ContactOper.MarkNum)
            {
                g_ContactsMng.InterfaceCtrl.SelAllFlg = TRUE;
                if (PHONE_TEXT_ID_SELECT_ALL == Interface->ContButton[0].TxtId)
                {
                    Image = lv_obj_get_child_back(Interface->ContButton[0].Button, NULL);
                    lv_img_set_src(Image, SYMBOL_CHECKED);
                }
            }

            Interface->ContButton[Interface->Index].SymbolId1 = SYMBOL_CHECKED;
        }
        Image = lv_obj_get_child_back(Interface->ContButton[Interface->Index].Button, NULL);
        lv_img_set_src(Image, Interface->ContButton[Interface->Index].SymbolId1);
    }
} /* Contacts_Com_Select_Multi_Contacts_Btn_Cb */

/**
 * Update the text of button with check box to select all in UI_Button_Container_Desc_t
 * param (in) ContBtn: UI_Button_Desc_t *
 * return  VOID
 */
VOID Contacts_Select_All_With_Check_Box(UI_Button_Desc_t *ContBtn)
{
    lv_obj_t   *Image2    = lv_obj_get_child(ContBtn->Button, NULL);
    lv_obj_t   *Label     = lv_obj_get_child(ContBtn->Button, Image2);
    lv_obj_t   *Image1    = lv_obj_get_child(ContBtn->Button, Label);
    lv_coord_t LabelWidth = lv_obj_get_width(Label);

    if (NULL != ContBtn->BtnTxt)
    {
        Hal_Mem_Free(ContBtn->BtnTxt);
        ContBtn->BtnTxt = NULL;
    }

    if (TRUE == g_ContactsMng.InterfaceCtrl.SelAllFlg)
    {
        ContBtn->SymbolId1 = SYMBOL_CHECKED;
    }
    else
    {
        ContBtn->SymbolId1 = SYMBOL_NOT_CHECKED;
    }
    ContBtn->TxtId = PHONE_TEXT_ID_SELECT_ALL;

    lv_img_set_src(Image1, ContBtn->SymbolId1);
    lv_label_set_long_mode(Label, LV_LABEL_LONG_EXPAND);
    lv_label_set_text_id(Label, PHONE_TEXT_ID_SELECT_ALL);
    lv_label_set_long_mode(Label, LV_LABEL_LONG_SROLL);
    lv_obj_set_width(Label, LabelWidth);
    lv_obj_set_hidden(Image2, true);

    g_ContactsMng.InterfaceCtrl.Focus = NULL;
}

/**
 * Update the description of buttons with check box in UI_Button_Container_Desc_t
 * param (in) Contact: Contacts_Info_t *
 * param (in) ContBtn: UI_Button_Desc_t *
 * return  VOID
 */
VOID Contacts_Update_ContBtn_Des_With_Check_Box(Contacts_Info_t *Contact, UI_Button_Desc_t *ContBtn)
{
    lv_obj_t   *Image2    = lv_obj_get_child(ContBtn->Button, NULL);
    lv_obj_t   *Label     = lv_obj_get_child(ContBtn->Button, Image2);
    lv_obj_t   *Image1    = lv_obj_get_child(ContBtn->Button, Label);
    UINT8      Len        = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH + 1;
    lv_coord_t LabelWidth = 0;

    if (true == lv_obj_get_hidden(Image2))
    {
        lv_obj_set_hidden(Image2, false);
    }

    if (NULL == ContBtn->BtnTxt)
    {
        ContBtn->BtnTxt = (INT8 *)Hal_Mem_Alloc(Len);
        Hal_Mem_Set(ContBtn->BtnTxt, 0, Len);
    }
    sprintf(ContBtn->BtnTxt, "%s\n%s", Contact->Name, Contact->Number);

    if (LV_LANG_TXT_ID_NONE != ContBtn->TxtId)
    {
        LabelWidth = lv_obj_get_width(Label);
        lv_label_set_long_mode(Label, LV_LABEL_LONG_EXPAND);
    }
    lv_label_set_text(Label, ContBtn->BtnTxt);
    if (LV_LANG_TXT_ID_NONE != ContBtn->TxtId)
    {
        lv_label_set_long_mode(Label, LV_LABEL_LONG_SROLL);
        lv_obj_set_width(Label, LabelWidth);
        ContBtn->TxtId = LV_LANG_TXT_ID_NONE;
    }
    if (TRUE == Contact->MarkFlg)
    {
        ContBtn->SymbolId1 = SYMBOL_CHECKED;
    }
    else
    {
        ContBtn->SymbolId1 = SYMBOL_NOT_CHECKED;
    }
    lv_img_set_src(Image1, ContBtn->SymbolId1);
    ContBtn->SymbolId2 = Contacts_Get_Contact_Memory_Symbol(Contact->MemoryAndIndex);
    lv_img_set_src(Image2, ContBtn->SymbolId2);
}

/**
 * Press direction key on the interface to select multiple contacts
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Com_Select_Multi_Press_Direction_Key(UI_KEY_VALUE Key_Val)
{
    UI_Button_Container_Desc_t *Interface =
        &(((UI_Normal_Button_Container_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl)->ButtonContainer);
    UINT8                      Ret          = 1;
    Contacts_List_t            *Contact     = g_ContactsMng.InterfaceCtrl.Focus;
    Contacts_List_t            *ContactPrev = NULL;
    Contacts_List_t            *ContactNext = NULL;
    UINT16                     ContactTotal;
    UI_Button_Desc_t           *ContBtn[UI_MAX_CONT_BTN_NUM];
    lv_obj_t                   *Cont;
    lv_ll_t                    *ContactsList;
    INT16                      i;

    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        ContBtn[i] = &Interface->ContButton[i];
    }
    Cont = Interface->ContScrl.Container;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactTotal);

    if (0 == ContactTotal)
    {   /* Contact empty or only one contact, not move focus */
        return(Ret);
    }

    switch (Key_Val)
    {
    case KEY_UP:
    case KEY_LEFT:
        if (0 == Interface->Index)
        {
            if ((UI_MAX_CONT_BTN_NUM - 1) >= ContactTotal)  // focus on the select all button at the first position
            {
                /* jump to the tail of button */
                g_ContactsMng.InterfaceCtrl.Focus = _lv_ll_get_tail(ContactsList);
                Interface->Index                  = ContactTotal;
                Ret                               = 0;        // call the default key funtion to move focus
            }
            else
            {
                if (NULL != Contact) // focus on contact button
                {
                    /* only change button text to the previous contact, not move focus */
                    ContactPrev = _lv_ll_get_prev(ContactsList, Contact);
                    if (NULL == ContactPrev)
                    {
                        Contacts_Select_All_With_Check_Box(ContBtn[0]);
                    }
                    else
                    {
                        Contacts_Update_ContBtn_Des_With_Check_Box(ContactPrev->ContactInfo, ContBtn[0]);
                        g_ContactsMng.InterfaceCtrl.Focus = ContactPrev;
                    }
                    Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[1]);
                    for (i = 2;i < UI_MAX_CONT_BTN_NUM;i++)
                    {
                        Contact = _lv_ll_get_next(ContactsList, Contact);
                        Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[i]);
                    }
                    Interface->PosY -= Interface->Height;
                }
                else // focus on the select all button at the first position
                {
                    /* jump to the tail */
                    Contact = _lv_ll_get_tail(ContactsList);
                    g_ContactsMng.InterfaceCtrl.Focus = Contact;
                    for (i = UI_MAX_CONT_BTN_NUM - 1;i >= 0;i--)
                    {
                        Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[i]);
                        Contact = _lv_ll_get_prev(ContactsList, Contact);
                    }

                    Interface->Index = UI_MAX_CONT_BTN_NUM - 1;
                    Interface->PosY  = Interface->Height * (ContactTotal + 1 - UI_MAX_CONT_BTN_NUM);

                    Ret = 0;
                }
            }
        }
        else
        {
            ContactPrev = _lv_ll_get_prev(ContactsList, Contact);
            if (NULL == ContactPrev)
            {
                g_ContactsMng.InterfaceCtrl.Focus = NULL;
            }
            else
            {
                g_ContactsMng.InterfaceCtrl.Focus = ContactPrev;
            }
            Interface->Index--;

            Ret = 0; // call the default key function
        }

        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->List,
                                             (ContactTotal + 1) * Interface->Height,
                                             - Interface->PosY);
        break;

    case KEY_DOWN:
    case KEY_RIGHT:
        if ((UI_MAX_CONT_BTN_NUM - 1) >= ContactTotal)
        {
            if (ContactTotal == Interface->Index)
            {
                g_ContactsMng.InterfaceCtrl.Focus = NULL;
                Interface->Index                  = 0;
            }
            else
            {
                if (NULL == Contact) // focus on select all button at the first position
                {
                    g_ContactsMng.InterfaceCtrl.Focus = _lv_ll_get_head(ContactsList);
                }
                else
                {
                    g_ContactsMng.InterfaceCtrl.Focus = _lv_ll_get_next(ContactsList, Contact);
                }

                Interface->Index++;
            }

            Ret = 0; // call the default key function
        }
        else
        {
            if ((UI_MAX_CONT_BTN_NUM - 1) == Interface->Index)   // focus on the last button
            {
                ContactNext = _lv_ll_get_next(ContactsList, Contact);
                if (NULL == ContactNext) // at the tail of contact list
                {
                    /* jump to select all button at the first postion */
                    Contacts_Select_All_With_Check_Box(ContBtn[0]);

                    Contact = _lv_ll_get_head(ContactsList);
                    for (i = 1;i < UI_MAX_CONT_BTN_NUM;i++)
                    {
                        Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[i]);
                        Contact = _lv_ll_get_next(ContactsList, Contact);
                    }

                    Interface->Index = 0;
                    Interface->PosY  = 0;

                    Ret = 0;
                }
                else
                {
                    /* only change button text to the next contact, not move focus */
                    Contacts_Update_ContBtn_Des_With_Check_Box(ContactNext->ContactInfo, ContBtn[UI_MAX_CONT_BTN_NUM - 1]);
                    g_ContactsMng.InterfaceCtrl.Focus = ContactNext;
                    Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[UI_MAX_CONT_BTN_NUM - 2]);
                    for (i = UI_MAX_CONT_BTN_NUM - 3;i >= 0;i--)
                    {
                        Contact = _lv_ll_get_prev(ContactsList, Contact);
                        Contacts_Update_ContBtn_Des_With_Check_Box(Contact->ContactInfo, ContBtn[i]);
                    }

                    Interface->PosY += Interface->Height;
                }
            }
            else
            {
                if (NULL == Contact) // focus on select all button at the first position
                {
                    g_ContactsMng.InterfaceCtrl.Focus = _lv_ll_get_head(ContactsList);
                }
                else
                {
                    g_ContactsMng.InterfaceCtrl.Focus = _lv_ll_get_next(ContactsList, Contact);
                }
                Interface->Index++;

                Ret = 0; // call the default key function
            }
        }

        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->List,
                                             (ContactTotal + 1) * Interface->Height,
                                             - Interface->PosY);
        break;

    default:
        break;
    } /* switch */

    return(Ret);
} /* Contacts_Com_Select_Multi_Press_Direction_Key */

/**
 * Callback function for destroying the interface which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_Multi_Contacts_OnDestroy(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    Contacts_List_t                   *Contact;
    lv_ll_t                           *ContactsList;
    UINT16                            i;
    UINT16                            MarkNum = g_ContactsMng.ContactOper.MarkNum;

    printf("%s: action %d\n", __FUNCTION__, g_ContactsMng.ContactOper.Action);
    ContactsList = Contacts_Get_Contacts_Operation_List(NULL);

    Contact = _lv_ll_get_head(ContactsList);
    while ((0 < MarkNum) && Contact)
    {
        if (TRUE == Contact->ContactInfo->MarkFlg)
        {
            Contact->ContactInfo->MarkFlg = FALSE;
            MarkNum--;
        }
        Contact = _lv_ll_get_next(ContactsList, Contact);
    }
    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        if (NULL != Interface->ButtonContainer.ContButton[i].BtnTxt)
        {
            Hal_Mem_Free(Interface->ButtonContainer.ContButton[i].BtnTxt);
        }
    }
    Hal_Mem_Free(Ctrl);
    g_ContactsMng.InterfaceCtrl.SelAllFlg = FALSE;
    if ((CONTACTS_ACTION_COPY == g_ContactsMng.ContactOper.Action)
        || (CONTACTS_ACTION_MOVE == g_ContactsMng.ContactOper.Action))
    {
        _lv_ll_clear(&g_ContactsMng.ContactOper.SrcMemList);
        if (0 == g_ContactsMng.ContactOper.WaitCnfBitmap)
        {
            g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_NULL;
        }
    }
} /* Contacts_Com_Select_Multi_Contacts_OnDestroy */

/**
 * Callback function for additional actions after Creating interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_Multi_Contacts_OnCreate(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t                          *Cont      = Interface->ButtonContainer.ContScrl.Container;
    lv_obj_t                          *Image;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    if (PHONE_TEXT_ID_EMPTY == Interface->Label.TxtId)
    {
        return;
    }

    Image = lv_obj_get_child(Interface->ButtonContainer.ContButton[0].Button, NULL);
    lv_obj_set_hidden(Image, true);

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    ContactsCount++;
    ScrlH = ContactsCount * Interface->ButtonContainer.Height;
    Contacts_Set_ScrlBar_Size_For_BtnCont(Cont,
                                          Interface->ButtonContainer.List,
                                          ScrlH);
    Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                         Interface->ButtonContainer.List,
                                         ScrlH,
                                         Interface->ButtonContainer.PosY);
}

/**
 * Callback function for restoring state after backward from another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Com_Select_Multi_Contacts_OnRestoreState(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t                          *Cont      = Interface->ButtonContainer.ContScrl.Container;
    lv_obj_t                          *Image;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    g_ContactsMng.InterfaceCtrl.Ctrl = Ctrl;

    if (PHONE_TEXT_ID_EMPTY == Interface->Label.TxtId)
    {
        return;
    }

    if (PHONE_TEXT_ID_SELECT_ALL == Interface->ButtonContainer.ContButton[0].TxtId)
    {
        Image = lv_obj_get_child(Interface->ButtonContainer.ContButton[0].Button, NULL);
        lv_obj_set_hidden(Image, true);
    }

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    ContactsCount++;
    ScrlH = ContactsCount * Interface->ButtonContainer.Height;
    Contacts_Set_ScrlBar_Size_For_BtnCont(Cont,
                                          Interface->ButtonContainer.List,
                                          ScrlH);
    Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                         Interface->ButtonContainer.List,
                                         ScrlH,
                                         Interface->ButtonContainer.PosY);
}

/**
 * Common function for selecting multiple contacts
 * param (in) DestActId: ACTIVITY_ID
 * param (in) KeyFunc: UI_Handle_Key_CallBack *
 * return  VOID
 */
VOID Contacts_Com_Create_Select_Multi_Contacts(ACTIVITY_ID            DestActId,
                                               UI_Handle_Key_CallBack *KeyFunc)
{
    UI_Normal_Button_Container_Desc_t *Interface;
    Nav_Func_List_t                   FuncList;
    UINT8                             Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH +
                                            1;
    Contacts_List_t                   *Contact;
    lv_ll_t                           *ContactsList;
    UINT16                            ContactsCount;
    UINT8                             i;

    Interface =
        (UI_Normal_Button_Container_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_Button_Container_Desc_t));
    Hal_Mem_Set(Interface, 0, sizeof(UI_Normal_Button_Container_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = DestActId;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)Interface;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactsCount);

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_1,
               "Contacts_Com_Create_Select_Multi_Contacts, ContactsCount %d, MarkNum %d\n",
               ContactsCount, g_ContactsMng.ContactOper.MarkNum);

    g_ContactsMng.ContactOper.MarkNum = 0;

    Interface->TitleBar.TxtId      = PHONE_TEXT_ID_CONTACT;
    Interface->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    if (0 == ContactsCount)
    {
        Interface->Label.TxtAlign   = LV_LABEL_ALIGN_CENTER;
        Interface->Label.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
        Interface->Label.TxtId      = PHONE_TEXT_ID_EMPTY;
    }
    else
    {
        Interface->ButtonContainer.ContButton[0].Valid  = TRUE;
        Interface->ButtonContainer.ContButton[0].TxtId  = PHONE_TEXT_ID_SELECT_ALL;
        Interface->ButtonContainer.ContButton[0].BtnTxt = NULL;
        Interface->ButtonContainer.ContButton[0].SymbolId1  = SYMBOL_NOT_CHECKED;
        Interface->ButtonContainer.ContButton[0].SymbolId2  = SYMBOL_PHONE;
        Interface->ButtonContainer.ContButton[0].ReleaseFun = Contacts_Com_Select_Multi_Contacts_Btn_Cb;
        g_ContactsMng.InterfaceCtrl.Focus                   = NULL;
        g_ContactsMng.InterfaceCtrl.SelAllFlg               = FALSE;

        Contact = _lv_ll_get_head(ContactsList);
        for (i = 1;i < UI_MAX_CONT_BTN_NUM;i++)
        {
            if (Contact)
            {
                Interface->ButtonContainer.ContButton[i].Valid     = TRUE;
                Interface->ButtonContainer.ContButton[i].TxtId     = LV_LANG_TXT_ID_NONE;
                Interface->ButtonContainer.ContButton[i].SymbolId1 = SYMBOL_NOT_CHECKED;
                Interface->ButtonContainer.ContButton[i].SymbolId2 = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
                Interface->ButtonContainer.ContButton[i].BtnTxt    = (INT8 *)Hal_Mem_Alloc(Len);
                sprintf(Interface->ButtonContainer.ContButton[i].BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
                Interface->ButtonContainer.ContButton[i].ReleaseFun =
                    Contacts_Com_Select_Multi_Contacts_Btn_Cb;

                Contact = _lv_ll_get_next(ContactsList, Contact);
            }
            else
            {
                break;
            }
        }

        /* if (0 != (FP_CONT_BAR_H % (ContactsCount + 1))) */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / (ContactsCount + 1) + 1; */
        /* } */
        /* else */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / (ContactsCount + 1); */
        /* } */
        Interface->ButtonContainer.Height = FP_CONT_BAR_H / UI_MAX_CONT_BTN_NUM;
    }

    Interface->ButtonBar.ButtonL.ButtonIndex = 0;
    Interface->ButtonBar.ButtonL.Valid       = TRUE;
    if (ACT_ID_CONTACTS_DELETE == DestActId)
    {
        Interface->ButtonBar.ButtonL.TxtId = PHONE_TEXT_ID_DELETE;
    }
    else if (ACT_ID_CONTACTS_COPY == DestActId)
    {
        Interface->ButtonBar.ButtonL.TxtId = PHONE_TEXT_ID_COPY;
    }
    else if (ACT_ID_CONTACTS_MOVE == DestActId)
    {
        Interface->ButtonBar.ButtonL.TxtId = PHONE_TEXT_ID_MOVE;
    }
    else if (ACT_ID_CONTACTS_SELECT_MULTI == DestActId)
    {
        Interface->ButtonBar.ButtonL.TxtId = PHONE_TEXT_ID_OK;
    }

    Interface->ButtonBar.ButtonM.ButtonIndex = 1;
    Interface->ButtonBar.ButtonM.Valid       = TRUE;
    Interface->ButtonBar.ButtonM.TxtId       = PHONE_TEXT_ID_SELECT;

    Interface->ButtonBar.ButtonR.ButtonIndex = 2;
    Interface->ButtonBar.ButtonR.Valid       = TRUE;
    Interface->ButtonBar.ButtonR.TxtId       = PHONE_TEXT_ID_BACK;

    Interface->KeyFunc = KeyFunc;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_Button_Container_Create;
    FuncList.OnCreate       = Contacts_Com_Select_Multi_Contacts_OnCreate;
    FuncList.OnRestoreState = Contacts_Com_Select_Multi_Contacts_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Com_Select_Multi_Contacts_OnDestroy;

    Nav_Forward(ACT_ID_ANY, DestActId, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Com_Create_Select_Multi_Contacts */

/**
 * Callback function for handling key pressed on Contacts_Select_Multi interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Select_Multi_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta, UI_KEY_VALUE Key_Val)
{
    UINT8                Ret = 1;
    Contacts_List_t      *Contact;
    UINT16               ContactTotal;
    lv_ll_t              *ContactsList;
    UINT16               Index;
    If_Contacts_Select_t *ContactSel;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactTotal);

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_UP:
        case KEY_LEFT:
        case KEY_DOWN:
        case KEY_RIGHT:
            Ret = Contacts_Com_Select_Multi_Press_Direction_Key(Key_Val);
            break;

        case KEY_OK:
            if (0 != ContactTotal)
            {
                Ret = 0; // call the default key function
            }
            break;

        case KEY_SOFTLEFT: // transfer marked contacts to source module
            if (0 != g_ContactsMng.ContactOper.MarkNum)
            {
                ContactSel = (If_Contacts_Select_t *)Hal_Mem_Alloc(sizeof(If_Contacts_Select_t) * g_ContactsMng.ContactOper.MarkNum);

                Index   = 0;
                Contact = _lv_ll_get_head(ContactsList);
                while (NULL != Contact)
                {
                    if (TRUE == Contact->ContactInfo->MarkFlg)
                    {
                        Hal_Mem_Copy(ContactSel[Index].Name, Contact->ContactInfo->Name, IF_CONTACTS_MAX_NAME_LENGTH);
                        Hal_Mem_Copy(ContactSel[Index].Number, Contact->ContactInfo->Number, IF_CONTACTS_MAX_NUMBER_LENGTH);
                        Index++;
                    }

                    Contact = _lv_ll_get_next(ContactsList, Contact);
                }

                if (Index != g_ContactsMng.ContactOper.MarkNum)
                {
                    /* error */
                }

                Contacts_SMS_Select_Contact_Cnf(ContactSel, Index);
            }
            break;

        case KEY_SOFTRIGHT:
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        default:
            break;
        } /* switch */
    }

    return(Ret);
} /* Contacts_Select_Multi_Key_Cb */

/**
 * Create Contacts_Select_Multi interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Select_Multi(VOID)
{
    Contacts_Com_Create_Select_Multi_Contacts(ACT_ID_CONTACTS_SELECT_MULTI, Contacts_Select_Multi_Key_Cb);
}

/**
 * Select contact request
 * param (in) Type: IF_CONTACTS_SEL_CONTACT_TYPE
 * return  VOID
 */
VOID Contacts_Select_Contact_Req(IF_CONTACTS_SEL_CONTACT_TYPE Type)
{
    g_ContactsMng.SelectContactType = Type;

    switch (Type)
    {
    case IF_CONTACTS_CALL_SEL_ONE_CONTACT:
    case IF_CONTACTS_SETTING_SEL_ONE_CONTACT:
    case IF_CONTACTS_SMS_SEL_ONE_CONTACT:
        Contacts_Create_Contacts_Select_One();
        break;

    case IF_CONTACTS_SMS_SEL_MULTI_CONTACTS:
        Contacts_Create_Contacts_Select_Multi();
        break;

    default:
        break;
    }
}
